#ifndef _ESC_MEM_H_
#define _ESC_MEM_H_

/*
 * Essential-C - Essential C Libraries for Developers
 * Copyright (c) 2004-2008 Tom Bradford <tom@tbradford.org>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a 
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 */

/**
 * Implements a concept called Memory Chains (for lack of a better
 * term).  Memory Chains allow a developer to manage a group of memory
 * allocations in a more atomic manner, and with greater flexibility.
 * The Chains support reference counted, explicit, and transactional
 * deallocation depending on the developer's needs.
 * 
 * Note: These functions are NOT thread-safe.  You must manage your
 * own mutexes if you plan on safely threading the reference counting
 * features.
 */

#include <stdlib.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus


/** Incomplete type for Memory Chain instances */
typedef struct esc_mem_t esc_mem_t;

/** Implementation type for Memory Function Table instances */
typedef struct {
    void* (*mallocFunction)(size_t size);
    void* (*reallocFunction)(void* ptr, size_t size);
    void* (*memsetFunction)(void* ptr, int c, size_t len);
    void (*freeFunction)(void* ptr);
} esc_mem_functions_t;

/** Function type for Reference disposal callbacks */
typedef void esc_ptr_disposal_t(void* ptr);

/** Create a Memory Chain instance with optional parent */
esc_mem_t* esc_mem_new(esc_mem_t* parentMem);

/** Allocates a block and returns its associated Reference */
void* esc_mem_malloc(esc_mem_t* mem, size_t size);

/** Allocates an array and returns its associated Reference */
void* esc_mem_calloc(esc_mem_t* mem, size_t count, size_t size);

/** Sets whether or not to clear allocated memory */
void esc_mem_setClearMemory(esc_mem_t* mem, bool clearMemory);

/** Returns whether or not to clear allocated memory */
bool esc_mem_isClearMemory(esc_mem_t* mem);

/** Sets the memory-related functions for the Memory Chain */
void esc_mem_setMemoryFunctions(esc_mem_t* mem,
                                esc_mem_functions_t* functions);

/** Returns the memory-related functions for the Memory Chain */
esc_mem_functions_t* esc_mem_getMemoryFunctions(esc_mem_t* mem);

/** Sets the disposal function associated with the Reference */
void esc_ptr_setDisposalFunction(void* ptr,
                                 esc_ptr_disposal_t* disposalFunction);

/** Returns the disposal function associated with the Reference */
esc_ptr_disposal_t* esc_ptr_getDisposalFunction(void* ptr);

/** 
 * Retains the specified Reference (increases its reference count).
 * Will accept a NULL pointer, resulting in a No-Op.
 */
void* esc_ptr_retain(void* ptr);

/** 
 * Releases the specified Pointer (decreases its reference count)
 * Will accept a NULL pointer, resulting in a No-Op.
 */    
void esc_ptr_release(void* ptr);

/** Resizes a block of memory */
void* esc_ptr_realloc(void* ptr, size_t size);

/** Explicitly frees a Reference's memory (ignoring reference count) */
void esc_ptr_free(void* ptr);

/** Returns the size of a Reference's memory */
size_t esc_ptr_getSize(void* ptr);

/** Returns the Reference's associated Memory Chain instance */
esc_mem_t* esc_ptr_getMem(void* ptr);


#ifdef __cplusplus
}
#endif // __cplusplus

#endif // _ESC_MEM_H_
